﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace colasContinua.Museo
{
    public class Museo
    {
        private static Museo museo;
        public Salas.SalaC salaC;
        public Salas.SalaD salaD;
        public double reloj { get; set; }
        public double proximaLlegada { get; set; }
        public double tEntreLlegadas { get; set; }
        public List<GrupoVisitante.GrupoVisita> grupos { get; set; }
        public List<string> vectorDeEstado { get; set; }
        public bool primeraCorrida = true;
        private double menorTiempo;
        private GrupoVisitante.GrupoVisita grupoSiguiente = null;
        public int colaMaxima = 0;
        public int totalVisitantes = 0;
        public int acuVisitantesPromedio = 0;
        public int NroGrupoVisitante { get; set; }

        public double proximoBloqueo { get; set; }
        public double horaDesbloqueo { get; set; }
        public Boolean sigueBloqueo = false;
        public Boolean sigueDesbloqueo = false;
        public Boolean bloqueoServidorC = false;
        
        private Museo()
        {
            salaC = Salas.SalaC.getInstancia();
            salaD = Salas.SalaD.getInstancia();
            reloj = 0.00;
            vectorDeEstado = new List<string>();
            grupos = new List<GrupoVisitante.GrupoVisita>();
        }

        public static Museo getInstancia()
        {
            if (museo == null)
            {
                museo = new Museo();
            }
            return museo;
        }

        public void generarProximaLlegada()
        {
            tEntreLlegadas = (-5 * (Math.Log(1 - new Random().NextDouble())));
            proximaLlegada = reloj + tEntreLlegadas;
            vectorDeEstado[2] = tEntreLlegadas.ToString();
            vectorDeEstado[3] = proximaLlegada.ToString();
        }

        public void simular(DataGridView grilla)
        {
            if (primeraCorrida)
            {
                inicializarVectorDeEstado();
                generarProximaLlegada();
                generarProximoBloqueo();
                vectorDeEstado[0] = reloj.ToString();
                vectorDeEstado[1] = Enumeraciones.EstadoEvento.Inicio.ToString();
                primeraCorrida = false;
                agregarColumnasIniciales(grilla);
            }
            else
	        {
                
                menorTiempo = proximaLlegada;
                grupoSiguiente = null;
                for (int i = 0; i < grupos.Count; i++)
                {
                    if ((grupos[i].EstadoVisita == Enumeraciones.EstadoGrupoVisita.recorriendoSalaC || grupos[i].EstadoVisita == Enumeraciones.EstadoGrupoVisita.recorriendoSalaD) && menorTiempo > grupos[i].HoraFinRecorrido)
                    {
                        menorTiempo = grupos[i].HoraFinRecorrido;
                        grupoSiguiente = grupos[i];
                    }
                    if ((menorTiempo > proximoBloqueo) && proximoBloqueo != 0)
                    {
                        sigueBloqueo = true;
                    }
                    else
                    {
                        sigueBloqueo = false;
                    }
                    if (proximoBloqueo == 0 && (menorTiempo > horaDesbloqueo))
                    {
                        sigueDesbloqueo = true;
                    }
                    else
                    {
                        sigueDesbloqueo = false;
                    }
                }

                if (grupoSiguiente == null && sigueBloqueo == false && sigueDesbloqueo == false)
                {
                    reloj = proximaLlegada;
                    generarProximaLlegada();
                    vectorDeEstado[0] = reloj.ToString();
                    vectorDeEstado[13] = string.Empty;
                    vectorDeEstado[1] = Enumeraciones.EstadoEvento.LLegada.ToString();
                    GrupoVisitante.GrupoVisita grupoNuevo = new GrupoVisitante.GrupoVisita();
                    grupoNuevo.nroVisita = NroGrupoVisitante;
                    NroGrupoVisitante++;
                    grupos.Add(grupoNuevo);
                    vectorDeEstado[4] = grupoNuevo.CantadidadLote.ToString();
                    vectorDeEstado[5] = grupoNuevo.Cantidad_DeSalas_A_Recorrer() > 1 ? "C-D" : "C";
                    totalVisitantes = totalVisitantes + grupoNuevo.CantadidadLote;
                    acuVisitantesPromedio = acuVisitantesPromedio + grupoNuevo.CantadidadLote;

                    if (grupoNuevo.SalaActual.disponibilidad >= grupoNuevo.CantadidadLote && bloqueoServidorC == false)
                    {
                        grupoNuevo.SalaActual.disminuirDisponibilidad(grupoNuevo.CantadidadLote);
                        grupoNuevo.HoraInicioRecorrido = reloj;
                        grupoNuevo.HoraFinRecorrido = reloj + grupoNuevo.SalaActual.calcularDuracionRecorrido();

                        if (grupoNuevo.SalaActual.nombre == 'C')
                        {
                            grupoNuevo.EstadoVisita = Enumeraciones.EstadoGrupoVisita.recorriendoSalaC;
                            vectorDeEstado[6] = grupoNuevo.SalaActual.disponibilidad.ToString();
                            vectorDeEstado[7] = grupoNuevo.SalaActual.calcularCola().ToString();
                        }
                        else
                        {
                            grupoNuevo.EstadoVisita = Enumeraciones.EstadoGrupoVisita.recorriendoSalaD;
                            vectorDeEstado[8] = grupoNuevo.SalaActual.disponibilidad.ToString();
                            vectorDeEstado[9] = grupoNuevo.SalaActual.calcularCola().ToString();
                        }

                        if (colaMaxima < salaC.calcularCola())
                        {
                            colaMaxima = salaC.calcularCola(); ;
                        }
                        vectorDeEstado[10] = colaMaxima.ToString();
                        
                        vectorDeEstado[11] = totalVisitantes.ToString();
                        vectorDeEstado[12] = acuVisitantesPromedio.ToString();

                        actualizarVectorDeEstado(grupoNuevo);
                       
                    }
                    else
                    {
                        grupoNuevo.SalaActual.incrementarCola(grupoNuevo);
                        if (grupoNuevo.SalaActual.nombre == 'C')
                        {
                            grupoNuevo.EstadoVisita = Enumeraciones.EstadoGrupoVisita.esperandoPorSalaC;
                            vectorDeEstado[6] = grupoNuevo.SalaActual.disponibilidad.ToString();
                            vectorDeEstado[7] = grupoNuevo.SalaActual.calcularCola().ToString();
                        }
                        else
                        {
                            grupoNuevo.EstadoVisita = Enumeraciones.EstadoGrupoVisita.esperandoPorSalaD;
                            vectorDeEstado[8] = grupoNuevo.SalaActual.disponibilidad.ToString();
                            vectorDeEstado[9] = grupoNuevo.SalaActual.calcularCola().ToString();
                        }

                        if (colaMaxima < salaC.calcularCola())
                        {
                            colaMaxima = salaC.calcularCola();
                        }
                        vectorDeEstado[10] = colaMaxima.ToString();

                        vectorDeEstado[11] = totalVisitantes.ToString();
                        vectorDeEstado[12] = acuVisitantesPromedio.ToString();

                        actualizarVectorDeEstado(grupoNuevo);
                    }
                }
                else if(sigueBloqueo == false && sigueDesbloqueo == false)
                {
                    reloj = grupoSiguiente.HoraFinRecorrido;
                    vectorDeEstado[0] = reloj.ToString();
                    vectorDeEstado[1] = Enumeraciones.EstadoEvento.FinRecorrido.ToString() + " " + grupoSiguiente.SalaActual.nombre;
                    vectorDeEstado[2] = string.Empty;
                    vectorDeEstado[4] = string.Empty;
                    vectorDeEstado[5] = string.Empty;
                    vectorDeEstado[13] = string.Empty;
                    grupoSiguiente.SalaActual.incrementarDisponibilidad(grupoSiguiente.CantadidadLote);
                    if (grupoSiguiente.SalaActual.nombre == 'C')
                    {
                        vectorDeEstado[6] = grupoSiguiente.SalaActual.disponibilidad.ToString();
                        vectorDeEstado[7] = grupoSiguiente.SalaActual.calcularCola().ToString();
                    }
                    else
                    {
                        vectorDeEstado[8] = grupoSiguiente.SalaActual.disponibilidad.ToString();
                        vectorDeEstado[9] = grupoSiguiente.SalaActual.calcularCola().ToString();
                    }
                    if (grupoSiguiente.SalaActual.calcularCola() > 0)
                    {
                        GrupoVisitante.GrupoVisita g = grupoSiguiente.SalaActual.cola[0];
                        if (grupoSiguiente.SalaActual.disponibilidad >= g.CantadidadLote)
                        {
                            g.SalaActual.disminuirDisponibilidad(g.CantadidadLote);
                            g.SalaActual.disminuirCola(g);
                            if (g.SalaActual.nombre == 'C')
                            {
                                g.EstadoVisita = Enumeraciones.EstadoGrupoVisita.recorriendoSalaC;
                                vectorDeEstado[6] = g.SalaActual.disponibilidad.ToString();
                                vectorDeEstado[7] = g.SalaActual.calcularCola().ToString();
                            }
                            else
                            {
                                g.EstadoVisita = Enumeraciones.EstadoGrupoVisita.recorriendoSalaD;
                                vectorDeEstado[8] = g.SalaActual.disponibilidad.ToString();
                                vectorDeEstado[9] = g.SalaActual.calcularCola().ToString();
                            }
                            g.HoraInicioRecorrido = reloj;
                            g.HoraFinRecorrido = reloj + g.SalaActual.calcularDuracionRecorrido();
                            modificarVectorDeEstado(g);
                        }
                    }
                    grupoSiguiente.cantSalasPorRecorrer--;
                    if (grupoSiguiente.TieneProximoRecorrido())
                    {
                        if (grupoSiguiente.SalaActual.disponibilidad >= grupoSiguiente.CantadidadLote)
                        {
                            grupoSiguiente.SalaActual.disminuirDisponibilidad(grupoSiguiente.CantadidadLote);

                            if (grupoSiguiente.SalaActual.nombre == 'C')
                            {
                                grupoSiguiente.EstadoVisita = Enumeraciones.EstadoGrupoVisita.recorriendoSalaC;
                                vectorDeEstado[6] = grupoSiguiente.SalaActual.disponibilidad.ToString();
                                vectorDeEstado[7] = grupoSiguiente.SalaActual.calcularCola().ToString();
                            }
                            else
                            {
                                grupoSiguiente.EstadoVisita = Enumeraciones.EstadoGrupoVisita.recorriendoSalaD;
                                vectorDeEstado[8] = grupoSiguiente.SalaActual.disponibilidad.ToString();
                                vectorDeEstado[9] = grupoSiguiente.SalaActual.calcularCola().ToString();
                            }
                            grupoSiguiente.HoraInicioRecorrido = reloj;
                            grupoSiguiente.HoraFinRecorrido = reloj + grupoSiguiente.SalaActual.calcularDuracionRecorrido();
                            modificarVectorDeEstado(grupoSiguiente);
                        }
                        else
                        {
                            grupoSiguiente.SalaActual.incrementarCola(grupoSiguiente);
                            if (grupoSiguiente.SalaActual.nombre == 'C')
                            {
                                grupoSiguiente.EstadoVisita = Enumeraciones.EstadoGrupoVisita.esperandoPorSalaC;
                                vectorDeEstado[6] = grupoSiguiente.SalaActual.disponibilidad.ToString();
                                vectorDeEstado[7] = grupoSiguiente.SalaActual.calcularCola().ToString();
                            }
                            else
                            {
                                grupoSiguiente.EstadoVisita = Enumeraciones.EstadoGrupoVisita.esperandoPorSalaD;
                                vectorDeEstado[8] = grupoSiguiente.SalaActual.disponibilidad.ToString();
                                vectorDeEstado[9] = grupoSiguiente.SalaActual.calcularCola().ToString();
                            }

                            if (colaMaxima < salaC.calcularCola())
                            {
                                colaMaxima = salaC.calcularCola();
                            }
                            vectorDeEstado[10] = colaMaxima.ToString();

                            vectorDeEstado[11] = totalVisitantes.ToString();
                            vectorDeEstado[12] = acuVisitantesPromedio.ToString();

                            actualizarVectorDeEstado(grupoSiguiente);
                        }
                    }
                    else
                    {
                        blanquerPosicionVectorEstado(grupoSiguiente);
                        grupos.Remove(grupoSiguiente);
                    }

                }
                else
                {
                    if (sigueBloqueo == true)
                    {
                        reloj = proximoBloqueo;
                        vectorDeEstado[0] = reloj.ToString();
                        vectorDeEstado[1] = Enumeraciones.EstadoEvento.FinEstabilidadSist.ToString();
                        vectorDeEstado[2] = string.Empty;
                        vectorDeEstado[4] = string.Empty;
                        vectorDeEstado[5] = string.Empty;
                        vectorDeEstado[14] = string.Empty;
                        vectorDeEstado[15] = "Bloqueado";
                        horaDesbloqueo = reloj + 10;
                        vectorDeEstado[16] = horaDesbloqueo.ToString();

                        for (int i = 0; i < grupos.Count - 1; i++)
                        {
                            if (grupos[i].EstadoVisita == Enumeraciones.EstadoGrupoVisita.recorriendoSalaC)
                            {
                                grupos[i].HoraFinRecorrido = grupos[i].HoraFinRecorrido + 10;
                            }
                        }
                        sigueBloqueo = false;
                        proximoBloqueo = 0;
                        bloqueoServidorC = true;
                    }
                    else if (sigueDesbloqueo == true)
                    {
                        reloj = horaDesbloqueo;
                        vectorDeEstado[0] = horaDesbloqueo.ToString();
                        vectorDeEstado[1] = Enumeraciones.EstadoEvento.FinBloqueo.ToString();
                        vectorDeEstado[2] = string.Empty;
                        vectorDeEstado[4] = string.Empty;
                        vectorDeEstado[5] = string.Empty;
                        generarProximoBloqueo();
                        bloqueoServidorC = false;
                        sigueDesbloqueo = false;
                    }
                    
                }
	        }

            if (vectorDeEstado.Count == grilla.Columns.Count)
            {
                grilla.Rows.Add(vectorDeEstado.ToArray());
                int nroFilas = grilla.Rows.Count - 2;
                if (grilla[1, nroFilas].Value.ToString().Contains("FinEstabilidadSist"))
                {

                    grilla[1, nroFilas].Style.BackColor = System.Drawing.Color.Red;
                }
                else if (grilla[1, nroFilas].Value.ToString().Contains("FinBloqueo"))
                {
                    grilla[1, nroFilas].Style.BackColor = System.Drawing.Color.Green;
                }
            }
            else
            {
                int nro = vectorDeEstado.Count + 1;
                int nroFilas = grilla.Rows.Count - 2;
                grilla.Columns.Add("Col" + vectorDeEstado.Count, "Estado");
                grilla.Columns.Add("Col" + nro, "Hora fin recorrido sala");
                grilla.Rows.Add(vectorDeEstado.ToArray());

                if (grilla[1, nroFilas].Value.ToString().Contains("FinEstabilidadSist"))
                {

                    grilla[1, nroFilas].Style.BackColor = System.Drawing.Color.Red;
                }
                else if (grilla[1, nroFilas].Value.ToString().Contains("FinBloqueo"))
                {
                    grilla[1, nroFilas].Style.BackColor = System.Drawing.Color.Green;
                }
            }
        }

        public void actualizarVectorDeEstado(GrupoVisitante.GrupoVisita grupo)
        {
            if (vectorDeEstado.Count > 17)
            {
                bool encontre = false;
                for (int i = 17; i < vectorDeEstado.Count - 1; i = i + 2)
                {
                    if (vectorDeEstado[i] == string.Empty)
                    {
                        vectorDeEstado[i] = grupo.EstadoVisita.ToString() + " (" + grupo.nroVisita + ")";
                        vectorDeEstado[i + 1] = grupo.HoraFinRecorrido.ToString() + " (" + grupo.nroVisita + ")";
                        encontre = true;
                        break;
                    }
                }
                if (encontre == false)
                {
                    vectorDeEstado.Add(grupo.EstadoVisita.ToString() + " (" + grupo.nroVisita + ")");
                    vectorDeEstado.Add(grupo.HoraFinRecorrido.ToString() + " (" + grupo.nroVisita + ")");
                }
            }
            else
            {
                vectorDeEstado.Add(grupo.EstadoVisita.ToString() + " (" + grupo.nroVisita + ")");
                vectorDeEstado.Add(grupo.HoraFinRecorrido.ToString() + " (" + grupo.nroVisita + ")");
            }
        }

        public void modificarVectorDeEstado(GrupoVisitante.GrupoVisita grupo)
        {
            for (int i = 17; i < vectorDeEstado.Count - 1 ; i = i +2)
            {
                if (vectorDeEstado[i].Contains("(" + grupo.nroVisita + ")"))
                {
                    vectorDeEstado[i] = grupo.EstadoVisita.ToString() + " (" + grupo.nroVisita + ")";
                    vectorDeEstado[i + 1] = grupo.HoraFinRecorrido.ToString() + " (" + grupo.nroVisita + ")";
                    break;
                }
            }
        }

        public void blanquerPosicionVectorEstado(GrupoVisitante.GrupoVisita grupo)
        {
            for (int i = 17; i < vectorDeEstado.Count - 1; i = i + 2)
            {
                if (vectorDeEstado[i].Contains("(" + grupo.nroVisita + ")"))
                {
                    vectorDeEstado[i] = string.Empty;
                    vectorDeEstado[i + 1] = string.Empty;
                    break;
                }
            }
        }

        public void inicializarVectorDeEstado()
        {
            vectorDeEstado.Add("0.0");
            vectorDeEstado.Add("");
            vectorDeEstado.Add("-");
            vectorDeEstado.Add("-");
            vectorDeEstado.Add("-");
            vectorDeEstado.Add("-");
            vectorDeEstado.Add(salaC.disponibilidad.ToString());
            vectorDeEstado.Add(salaC.cola.Count.ToString());
            vectorDeEstado.Add(salaD.disponibilidad.ToString());
            vectorDeEstado.Add(salaD.cola.Count.ToString());
            vectorDeEstado.Add("0");
            vectorDeEstado.Add("0");
            vectorDeEstado.Add("0");
            vectorDeEstado.Add("");
            vectorDeEstado.Add("");
            vectorDeEstado.Add("");
            vectorDeEstado.Add("");
        }

        public void agregarColumnasIniciales(DataGridView grilla)
        {
            grilla.Columns.Add("col0", "Reloj");
            grilla.Columns.Add("col1", "Evento");
            grilla.Columns.Add("col2", "t entre llegadas");
            grilla.Columns.Add("col3", "Prox. llegada");
            grilla.Columns.Add("col4", "Tam. lote");
            grilla.Columns.Add("col5", "Recorrido");
            grilla.Columns.Add("col6", "Disp. C");
            grilla.Columns.Add("col7", "Cola C");
            grilla.Columns.Add("col8", "Disp D");
            grilla.Columns.Add("col9", "Cola D");
            grilla.Columns.Add("col10", "Cola MAX");
            grilla.Columns.Add("col11", "Total Vis.");
            grilla.Columns.Add("col12", "ACU vis");
            grilla.Columns.Add("col13", "RND");
            grilla.Columns.Add("col14", "Fin estabilidad sistema");
            grilla.Columns.Add("col15", "Estado Sala C");
            grilla.Columns.Add("col16", "Fin Bloqueo");
        }

        public void generarProximoBloqueo()
        {
            Random r = new Random();
            double x = r.NextDouble();
            vectorDeEstado[13] = x.ToString();
            proximoBloqueo = reloj + Metodos_numericos.rungeKutta.calcularTiempo(x);
            horaDesbloqueo = 0;
            vectorDeEstado[14] = proximoBloqueo.ToString();
            vectorDeEstado[15] = "Estable";
            vectorDeEstado[16] = string.Empty;
        }
    }
}
